package biz.datalk.industrialland.common.shiro;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.AuthenticationStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.authc.pam.ShortCircuitIterationException;
import org.apache.shiro.realm.Realm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;

/**
 *
 * 重写多realm校验方法，避免无法捕获到 realm 中的自定义异常
 *
 * @author tarofang@163.com
 * @date 2020-12-08
 */
// @Component("customModularRealmAuthenticator")
public class CustomModularRealmAuthenticator extends ModularRealmAuthenticator {
    private static final Logger log = LoggerFactory.getLogger(CustomModularRealmAuthenticator.class);

    /**
     * 重写多realm校验方法，避免无法捕获到 realm 中的自定义异常
     * 取消执行代码 realm.getAuthenticationInfo(token); 的try catch
     * 多个realm时候，如果其中一个realm抛出异常则直接抛出异常，类似single方法，
     */
    @Override
    protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
        // return super.doMultiRealmAuthentication(realms, token);
        AuthenticationStrategy strategy = getAuthenticationStrategy();

        AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);

        if (log.isTraceEnabled()) {
            log.trace("Iterating through {} realms for PAM authentication", realms.size());
        }

        for (Realm realm : realms) {
            try {
                aggregate = strategy.beforeAttempt(realm, token, aggregate);
            } catch (ShortCircuitIterationException shortCircuitSignal) {
                // Break from continuing with subsequnet realms on receiving
                // short circuit signal from strategy
                break;
            }
            if (realm.supports(token)) {
                log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);
                AuthenticationInfo info = null;
                Throwable t = null;
                // try {
                //     info = realm.getAuthenticationInfo(token);
                // } catch (Throwable throwable) {
                //     t = throwable;
                //     if (log.isDebugEnabled()) {
                //         String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:";
                //         log.debug(msg, t);
                //     }
                // }
                info = realm.getAuthenticationInfo(token);
                aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);
            } else {
                log.debug("Realm [{}] does not support token {}.  Skipping realm.", realm, token);
            }
        }

        aggregate = strategy.afterAllAttempts(token, aggregate);

        return aggregate;
    }
}
